package com.hiof.moraa.server.service;

import com.hiof.moraa.mapping.TblAthlete;
import com.hiof.moraa.mapping.TblTarget;
import com.hiof.moraa.server.dao.AthleteDAO;
import com.hiof.moraa.server.dao.AthleteLiveLocationDAO;
import com.hiof.moraa.server.dao.TargetDAO;
import com.hiof.moraa.server.service.model.*;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @author Bergy
 */
@Transactional(readOnly = true)
public class PassTargetService {

    private AthleteDAO athleteDAO;
    private TargetDAO targetDAO;
    private MapService mapService;
    private AthleteLiveLocationDAO athleteLiveLocationDAO;
    private GeometryService geometryService;
    private RouteGeographyService routeGeographyService;

    public void setAthleteDAO(AthleteDAO athleteDAO) {
        this.athleteDAO = athleteDAO;
    }

    public void setTargetDAO(TargetDAO targetDAO) {
        this.targetDAO = targetDAO;
    }

    public void setMapService(MapService mapService) {
        this.mapService = mapService;
    }

    public void setAthleteLiveLocationDAO(AthleteLiveLocationDAO athleteLiveLocationDAO) {
        this.athleteLiveLocationDAO = athleteLiveLocationDAO;
    }

    public void setGeometryService(GeometryService geometryService) {
        this.geometryService = geometryService;
    }

    public void setRouteGeographyService(RouteGeographyService routeGeographyService) {
        this.routeGeographyService = routeGeographyService;
    }

    public TargetInfoPacket getNextTargetInfo(int athleteId) {

        TblAthlete athlete = athleteDAO.getAthleteById(athleteId);
        int routeId = athlete.getTblRoute().getId();
        LiveLocationFeed liveLocationFeed = athleteLiveLocationDAO.getLatestLiveLocationFeedOfOneAthlete(athleteId);
        if (liveLocationFeed != null) {
            GeoPoint athleteGeoPoint = liveLocationFeed.getGoogleGeoPoint();
            List<TblTarget> targets = targetDAO.getListOfTargetInOneRoute(routeId);
            TblTarget nextTarget = getNextTarget(athleteGeoPoint, routeId, targets);
            try {
                return convert2NextTargetInfo(nextTarget, liveLocationFeed, mapService.getMapPoints(routeId));
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                return null;
            }
        } else {
            return null;
        }
    }

    private TblTarget getNextTarget(GeoPoint athleteGeoPoint, int routeId, List<TblTarget> targets) {
        List<MapPoint> mapPoints = mapService.getMapPoints(routeId);
        for (TblTarget tblTarget : targets) {
            boolean isPassed = routeGeographyService.checkPassTargetByGeometryAlgorithms(athleteGeoPoint, tblTarget.getGoogleGeoPoint(), mapPoints);
            if (!isPassed) {
                return tblTarget;
            }
        }
        return null;
    }

    private TargetInfoPacket convert2NextTargetInfo(TblTarget nextTarget, LiveLocationFeed athleteLiveLocation, List<MapPoint> mapPoints) throws Exception {
        if (nextTarget == null) {
            return new TargetInfoPacket("Already finished the race", 0, 0, athleteLiveLocation.getGoogleGeoPoint());
        } else {
            String targetName = nextTarget.getTargetName();
            double distance = routeGeographyService.distanceBetween2PointsInOneRoute(athleteLiveLocation.getGoogleGeoPoint(), nextTarget.getGoogleGeoPoint(), mapPoints);
            double predictedTime = geometryService.predictTimeBySpeedAndDistance(athleteLiveLocation.getSpeed(), distance);
            TargetInfoPacket packet = new TargetInfoPacket(targetName, predictedTime, distance, new GoogleGpsGeoPoint(nextTarget.getLat(), nextTarget.getLng(), nextTarget.getHeight()));
            return packet;
        }
    }
}
